/**
 * Copyright (c) 2010-2011 julewa.com.  
 * All rights reserved. 
 * 
 * @author Huang Benhua
 * @date 2011-2-20
 * 
**/
package com.julewa.freemarker;

import java.util.HashMap;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.views.freemarker.FreemarkerManager;
import org.apache.struts2.views.freemarker.ScopesHashModel;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

import com.julewa.Querier;
import com.julewa.db.Entity;
import com.julewa.freemarker.method.FM_UTILS;
import com.opensymphony.xwork2.util.ValueStack;

import freemarker.template.ObjectWrapper;
import freemarker.template.TemplateModelException;

public class FreemarkerLoader extends FreemarkerManager {

    private class MethodsMap extends HashMap<String, Object>{
		private static final long serialVersionUID = 1L;
		public Object put(String k, Object o){return null;};
    	void _put_(String k, Object o){
    		super.put(k, o);
    	}
    }

    private final MethodsMap methods=new MethodsMap();
	public FreemarkerLoader() throws TemplateModelException{
		this.loadMethods();
	}
	
	//
	private void push_fm_bean(String name, Class<?> clazz, Object bean){
		if(bean instanceof Querier){
			push(name,new FreemarkerMethod((Querier)bean));
			return;
		}
		Service s = clazz.getAnnotation(Service.class);
		if(s == null)return;
		Scope sc = clazz.getAnnotation(Scope.class);
		if(sc != null && Entity.SCOPE.equals(sc.value()))return;
		name = s.value();
		if(name == null || name.trim().equals("")){
			name = clazz.getSimpleName();
		};
		push(name, bean);
	}
	
    private void loadMethods() throws TemplateModelException{
		WebApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
		//get all services
		String names[] = ctx.getBeanDefinitionNames();
		for(String name: names){
			push_fm_bean(name, ctx.getType(name), ctx.getBean(name));
		}
		
		//put global values
		methods._put_("Utils", ctx.getBeansOfType(FM_UTILS.class).values().iterator().next());
    }
    
    private void push(String key, Object obj){
    	push(methods, 0, key.split("[.]"), obj);
    }
    
	private void push(MethodsMap map, int idx, String keys[], Object object){
    	String k = keys[idx].trim();
    	if((++idx) == keys.length){
    		map._put_(k, object);
    		return;
    	}
    	Object obj = map.get(k);
    	MethodsMap m = null;
    	if(obj == null){
    		m = new MethodsMap();
    		map._put_(k, m);
    	}else if(obj instanceof MethodsMap){
    		m = (MethodsMap)obj;
    	}else{
    		System.err.print("Failed to create freemarker method, there another method exists:" + obj.getClass().getName());
    		return;
    	}
		push(m, idx, keys, object);
    }
/*
    @Override
    public SimpleHash buildTemplateModel(
            ValueStack stack, Object action,
            ServletContext servletContext,
            HttpServletRequest request, HttpServletResponse response,
            ObjectWrapper wrapper) {
    	SimpleHash hash = super.buildTemplateModel(stack, action, servletContext, request, response, wrapper);
        hash.putAll(methods);
        hash.put("$ROOT$", hash);
        return hash;

    }
	
//*/	
	//*
    @Override
    public ScopesHashModel buildTemplateModel(
            ValueStack stack, Object action,
            ServletContext servletContext,
            HttpServletRequest request, HttpServletResponse response,
            ObjectWrapper wrapper) {
    	ScopesHashModel hash = super.buildTemplateModel(stack, action, servletContext, request, response, wrapper);
        hash.putAll(methods);
        hash.put("$ROOT$", hash);
        return hash;

    }
    //*/
}
